﻿// Agenda: A C# Agenda Library
//
// Copyright (c) 2010  Nuno A. Venâncio
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// Author:
// Nuno A. Venâncio (nunoavenancio@gmail.com)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;



namespace Agenda
{
  [DefaultEvent("SelectionChanged")]
  public partial class calendario :  UserControl
  {

    //Handle events
    public delegate void SelectionChangedHandler();
    [Category("Action")]
    [Description("Ocurres When Date Change")]
    public event SelectionChangedHandler SelectionChanged;
    protected virtual void OnSelectionChanged()
    {
      if (SelectionChanged != null)
      {
        SelectionChanged();
      }
    }

    //Culture Definition
    private System.Globalization.CultureInfo _cultureInfo = System.Threading.Thread.CurrentThread.CurrentUICulture;
    private System.Globalization.DateTimeFormatInfo dtfi ;
    private System.Globalization.Calendar _calendar = System.Globalization.CultureInfo.InvariantCulture.Calendar;
    //Datatble to construte the Gridcalendar datasource
    private DataTable _dtMes = new DataTable();
    //Array to have the date = _dtMes
    private DateTime[,] _dtMesArray = new DateTime[7,6];
    //Array to have the date for level paint
    //private DateTime[] _Nivel1Array= new DateTime[0];
    private DateTime[] _Nivel2Array = new DateTime[0];
    private DateTime[] _Nivel3Array = new DateTime[0];
    //Datatable to construte the CboxMes datasource
    private DataTable _dtMesNome = new DataTable();
    //Position of the weekend days in table
    private int[] _FimdeSemanaPosicao = new int[2];
    //Select Date
    private DateTime _SelectDay = DateTime.Today;
    //Find Selecte Day Position
    private int _SelectDayx = 0;
    private int _SelectDayy = 0;
    private bool _firststimerun = true;

    //Save position of days for future
    private int[] _PositionTodayDate = new int[2];
    private int[] _PositionSelect = new int[2];
    private int[] _PositionOldSelect = new int[2];
    #region Set Properties
    //Declare grid Calendar Properties

    //Default Values
    private System.Drawing.Color _BackColor;
    private System.Drawing.Color _FimDeSemanaColor = System.Drawing.SystemColors.ActiveCaption;
    private System.Drawing.Color _nivel1Color = System.Drawing.Color.LightGreen;
    private System.Drawing.Color _nivel2Color = System.Drawing.Color.Yellow;
    private System.Drawing.Color _nivel3Color = System.Drawing.Color.Red;
    private DayOfWeek _PriDiaSemana = DayOfWeek.Monday;

    private bool _nivelMostra = false;
    private bool _FimDeSemanaMostrar = false;
    #region Set values for properties

    /// <summary>
    /// Set Color for weekends
    /// </summary>
    [Category("Appearance")]
    [Description("Set/Get Color for WeekEnds days")]
    public System.Drawing.Color FimDeSemanaColor
    {
      get { return _FimDeSemanaColor;}
      set { _FimDeSemanaColor = value; }
      
    }
    /// <summary>
    /// Set Color for Level 1
    /// </summary>
    [Category("Appearance")]
    [Description("Set/Get Color for Level 1 Color")]
    public System.Drawing.Color nivel1Color
    {
      get { return _nivel1Color; }
      set { _nivel1Color = value; }
    }
    /// <summary>
    /// Set Color for Level 2
    /// </summary>
    [Category("Appearance")]
    [Description("Set/Get Color for Level 2 Color")]
    public System.Drawing.Color nivel2Color
    {
      get { return _nivel2Color; }
      set { _nivel2Color = value; }
    }
    /// <summary>
    /// Set Color for Level 3
    /// </summary>
    [Category("Appearance")]
    [Description("Set/Get Color for Level 3 Color")]
    public System.Drawing.Color nivel3Color
    {
      get { return _nivel3Color; }
      set { _nivel3Color = value; }
    }
    /// <summary>
    /// Set the Culture to show in Calendar
    /// </summary>
    public string setCulture
    {
      set { _cultureInfo = new System.Globalization.CultureInfo(value); }
    }
    /// <summary>
    /// Set the first day in week to show in Calendar
    /// </summary>
    [Category("Appearance")]
    [Description("Set/Get First Day of the  Week to show in Calendar")]
    public DayOfWeek PriDiaSemana
    {
      get {  return _PriDiaSemana; }
      set { _PriDiaSemana = value; }
    }
    /// <summary>
    /// Set paint level Days to show in calendar this disable weekends
    /// </summary>
    [Category("Appearance")]
    [Description("Set/Get Show in Color the Levels Days (This Disable FimdeSemana Porperties")]
    public bool NivelMostrar
    { 
      set { _nivelMostra = value; }
      get { return _nivelMostra ; } 
    }
    /// <summary>
    /// Set paint the weekends
    /// </summary>
    [Category("Appearance")]
    [Description("Set/Get To Show in Color the Weekend Days")]
    public bool FimDeSemanaMostrar
    {
      set { _FimDeSemanaMostrar = value; }
      get { return _FimDeSemanaMostrar ; } 
    }
    /// <summary>
    /// Set Maximum year for the Calendar
    /// </summary>
    [Category("Data")]
    [Description("Set/Get Maximum year to Visualise in Calendar")]
    public int MaxAno
    {
      get { return Convert.ToInt16(txtAno.Maximum); }
      set { txtAno.Maximum = value; }
    }
    /// <summary>
    /// Set Minimum year for the calendar
    /// </summary>
    [Category("Data")]
    [Description("Set/Get Minium year to Visualise in Calendar")]
    public int MinAno
    {
      get { return Convert.ToInt16(txtAno.Minimum) ; }
      set { txtAno.Minimum = value; }
    }
    /// <summary>
    /// Set MultiSelect days in calendar
    /// </summary>
    public bool multiSelect
    {
      set { gridCalandario.MultiSelect = value; }
    }
    //public DateTime SelecteDay
    //{
    //  set { _SelectDay = value; }
    //  get { return SelecteDay; }
    //}
    /// <summary>
    /// Get/Set the array for Level1 Color
    /// </summary>
    //public DateTime[] Nivel1Array
    //{
    //  set { _Nivel1Array= value;}
    //  get { return _Nivel1Array;}
    //}
    /// <summary>
    /// Get/Set the array for Level2 Color
    /// </summary>
    public DateTime[] Nivel2Array
    {
      set { _Nivel2Array = value; }
      get { return _Nivel2Array; }
    }
    /// <summary>
    /// Get/Set the array for Level1 Color
    /// </summary>
    public DateTime[] Nivel3Array
    {
      set { _Nivel3Array = value; }
      get { return _Nivel3Array; }
    }
    #endregion
    #endregion


    #region Initialize
    public calendario()
    {
      InitializeComponent();
      this.SuspendLayout();
      _BackColor = gridCalandario.DefaultCellStyle.BackColor;
      
    }

    #endregion

    public void iniciar()
    {
      this.gridCalandario.SelectionChanged -= new System.EventHandler(this.gridCalandario_SelectionChanged);
      dtfi = _cultureInfo.DateTimeFormat;
      
      _AdicionarColuna();
      mes(DateTime.Today.Month, DateTime.Today.Year);
      _preenchercBoxMes();
      gridCalandario.DataSource = _dtMes;
      _aspectoGrid();
      this.gridCalandario.SelectionChanged += new System.EventHandler(this.gridCalandario_SelectionChanged);
      if (_firststimerun)
      {
        this.gridCalandario.Rows[_SelectDayy].Cells[_SelectDayx].Selected = true;
        _firststimerun = false;
      }
    }
    /// <summary>
    /// Add the Columns to datatble with the name of abreviation day of week name
    /// </summary>
    private void _AdicionarColuna()
    {
      _dtMes.Reset();
      DateTime _data = DateTime.Now;
      //dtfi = _cultureInfo.DateTimeFormat;
      int _numPrimDiaSemana = Convert.ToInt32(_PriDiaSemana);
      int x = 0;
      int y = 0;
      for (int i = Convert.ToInt32(_PriDiaSemana); i < 7; i++)
      {
        _dtMes.Columns.Add(dtfi.GetAbbreviatedDayName(getDiaSemana(i)));
        if (getDiaSemana(i) == DayOfWeek.Saturday || getDiaSemana(i) == DayOfWeek.Sunday)
        {
          _FimdeSemanaPosicao[x] = y;
          x++;
        }
        y++;
      }
      for (int i = 0; i < Convert.ToInt32(_PriDiaSemana); i++)
      {
        _dtMes.Columns.Add(dtfi.GetAbbreviatedDayName(getDiaSemana(i)));
        if (getDiaSemana(i) == DayOfWeek.Saturday || getDiaSemana(i) == DayOfWeek.Sunday)
        {
          _FimdeSemanaPosicao[x] = y;
          x++;
        }
        y++;
      }
      
    }
    public DayOfWeek getDiaSemana(int diasemana)
    {
      DayOfWeek _dow = DayOfWeek.Monday;
      switch (diasemana)
      {
        case 0:
          {
            _dow = DayOfWeek.Sunday;
            break;
          }
        case 1:
          {
            _dow = DayOfWeek.Monday;
            break;
          }
        case 2:
          {
            _dow = DayOfWeek.Tuesday;
            break;
          }
        case 3:
          {
            _dow = DayOfWeek.Wednesday;
            break;
          }
        case 4:
          {
            _dow = DayOfWeek.Thursday;
            break;
          }
        case 5:
          {
            _dow = DayOfWeek.Friday;
            break;
          }
        case 6:
          {
            _dow = DayOfWeek.Saturday;
            break;
          }

      }
      return _dow;
    }
    /// <summary>
    /// Calculate the Month Stuture
    /// 
    /// </summary>
    /// <param name="_mes">Month to Build</param>
    /// <param name="_ano">Year to Build</param>
    private void mes(int _mes, int _ano)
    {

      DateTime  _IData = new DateTime(_ano, _mes, 1);
      _SelectDay = DateTime.Today;
      if (_PriDiaSemana == _IData.DayOfWeek)
        _IData= _IData.AddDays(-7);
      while (_PriDiaSemana != _IData.DayOfWeek)
        _IData = _IData.AddDays(-1);
      
      for (int i = 0; i < 6; i++)
      {
        DataRow _dr = _dtMes.NewRow();
        for (int j = 0; j < 7; j++)
        {
          _dtMesArray [j, i] = _IData.Date;
          _dr[j] = _IData.Day;
          
          if (_IData == _SelectDay && _firststimerun)
          {
            _SelectDayx = j;
            _SelectDayy = i;
            _PositionTodayDate[0] = j;
            _PositionTodayDate[1] = i;
            _PositionSelect[0] = j;
            _PositionSelect[1] = i;
          }
          _IData = _IData.AddDays(1);
        }
        _dtMes.Rows.Add(_dr);
      }
    }
    /// <summary>
    /// Set the size of cells a remove properties form gridCalendar
    /// </summary>
    public void _aspectoGrid()
    {
      this.gridCalandario.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;
      this.gridCalandario.AllowUserToResizeRows = false;
      this.gridCalandario.AllowUserToOrderColumns = false;
      this.gridCalandario.AllowUserToResizeColumns = false;
      this.gridCalandario.AllowUserToDeleteRows = false;
      this.gridCalandario.ScrollBars = System.Windows.Forms.ScrollBars.None;
      this.gridCalandario.SelectionMode = DataGridViewSelectionMode.CellSelect;

      foreach (DataGridViewColumn _cl in this.gridCalandario.Columns)
      {
        _cl.Width = this.gridCalandario.Size.Width / 7;
      }
      foreach (DataGridViewRow _dr in this.gridCalandario.Rows)
      {
        _dr.Height = (this.gridCalandario.Size.Height - this.gridCalandario.ColumnHeadersHeight) / 6;
      }
      foreach (DataGridViewColumn _cl in this.gridCalandario.Columns)
        _cl.SortMode = DataGridViewColumnSortMode.NotSortable;

      //reset colors
      for (int x = 0; x < 7; x++)
      {
        for (int y = 0; y < 6; y++)
        {
          //gridCalandario.DefaultCellStyle.BackColor = _BackColor;
          gridCalandario[x, y].Style.BackColor = _BackColor;
        }
      }
      
      //pAINT lEVELS aRRAY DATETIME
      if (_nivelMostra)
      {
        //Paint all with level 1 color
        for (int i = 0; i < 7; i++)
        {
          for (int j = 0; j < 6; j++)
          {
            gridCalandario[i, j].Style.BackColor = _nivel1Color;

          }
        }
        if (_Nivel2Array.Length > 0)
        {
          Array.Sort(_Nivel2Array);
          foreach (DateTime _n2 in _Nivel2Array)
          {
            if (_n2.Month == Convert.ToInt16(cBoxMes.SelectedValue))
            {
              for (int y = 0; y < 6; y++)
              {
                for (int x = 0; x < 7; x++)
                {
                  if (_n2.Date == _dtMesArray[x, y].Date)
                  {
                    gridCalandario[x, y].Style.BackColor = _nivel2Color;
                  }
                }
              }
            }
          }
        }
        if (_Nivel3Array.Length > 0)
        {
          Array.Sort(_Nivel3Array);
          foreach (DateTime _n3 in _Nivel3Array)
          {
            if (_n3.Month == Convert.ToInt16(cBoxMes.SelectedValue))
            {
              for (int j = 0; j < 6; j++)
              {
                for (int i = 0; i < 7; i++)
                {
                  if (_n3.Date == _dtMesArray[i, j].Date)
                  {
                    gridCalandario[i, j].Style.BackColor = _nivel3Color;
                  }
                }
              }
            }
          }
        }
      }
      //Paint Weekends
      if (this.gridCalandario.Columns.Count == 7 && _FimDeSemanaMostrar && !_nivelMostra)
      {
        for (int x = 0; x < _FimdeSemanaPosicao.Length; x++)
        {
          //this.gridCalandario.Columns[_FimdeSemanaPosicao[i]].DefaultCellStyle.BackColor = _FimDeSemanaColor;
          //this.gridCalandario.Columns[_FimdeSemanaPosicao[i]].DefaultCellStyle.BackColor = _FimDeSemanaColor;
          for (int y = 0; y < 6; y++)
          {
            gridCalandario[_FimdeSemanaPosicao[x], y].Style.BackColor = _FimDeSemanaColor;
          }
        }
      }
      //Paint the non days of month select
      for (int y = 0; y < 6; y++)
      {
        for (int x = 0; x < 7; x++)
        {
          if (_dtMesArray[x, y].Month != Convert.ToInt32(cBoxMes.SelectedValue))
          {
            this.gridCalandario[x, y].Style.BackColor = System.Drawing.Color.LightGray;
          }
        }
      }
      //Today Day Font Color
      if (Convert.ToInt16(cBoxMes.SelectedValue) == DateTime.Today.Month && Convert.ToInt16(txtAno.Value) == DateTime.Today.Year)
      {
        gridCalandario[_PositionTodayDate[0], _PositionTodayDate[1]].Style.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
        gridCalandario[_PositionTodayDate[0], _PositionTodayDate[1]].Style.ForeColor = System.Drawing.Color.Violet;
        gridCalandario[_PositionTodayDate[0], _PositionTodayDate[1]].Style.SelectionForeColor = System.Drawing.Color.Violet;
      }
      else
      {
        int _temp = _PositionTodayDate[0];
        if (_temp == 6)
          _temp--;
        else
          _temp++;
        gridCalandario[_PositionTodayDate[0], _PositionTodayDate[1]].Style.Font = gridCalandario[_temp, _PositionTodayDate[1]].Style.Font;
        gridCalandario[_PositionTodayDate[0], _PositionTodayDate[1]].Style.ForeColor = gridCalandario[_temp, _PositionTodayDate[1]].Style.ForeColor;
        gridCalandario[_PositionTodayDate[0], _PositionTodayDate[1]].Style.SelectionForeColor = gridCalandario[_temp, _PositionTodayDate[1]].Style.SelectionForeColor;
      }
      
    }

    /// <summary>
    /// fill the cBocMes with the Month values ( monthName = display member, Month Number = value Member
    /// </summary>
    private void _preenchercBoxMes()
    {
      this.cBoxMes.SelectedIndexChanged -= new System.EventHandler(this.cBoxMes_SelectedIndexChanged);
      _dtMesNome.Columns.Add("Mes");
      _dtMesNome.Columns.Add("value");
      
      DateTime _data = DateTime.Now;
      for (int i = 1; i <= 12; i++)
      {
        DataRow _dr = _dtMesNome.NewRow();
        _data = new DateTime(2010,i,1);
        _dr[0] = _data.ToString("MMMM");
        _dr[1] = i;
        _dtMesNome.Rows.Add(_dr);
      }
      cBoxMes.DataSource = _dtMesNome;
      cBoxMes.DisplayMember = "Mes";
      cBoxMes.ValueMember = "value";
      cBoxMes.SelectedIndex = DateTime.Now.Month-1;
      this.cBoxMes.SelectedIndexChanged += new System.EventHandler(this.cBoxMes_SelectedIndexChanged);
    }
    private void alterarMes()
    {
      this.gridCalandario.SelectionChanged -= new System.EventHandler(this.gridCalandario_SelectionChanged);
      _dtMes = new DataTable();
      _AdicionarColuna();
      
      mes(Convert.ToInt32(cBoxMes.SelectedValue), Convert.ToInt32(txtAno.Value));
      gridCalandario.DataSource = _dtMes;
      

      if (txtAno.Value == txtAno.Minimum && (Convert.ToInt32(cBoxMes.SelectedValue) == 1))
        btnMenos.Enabled = false;
      else
        btnMenos.Enabled = true;
      if (txtAno.Value == txtAno.Maximum && (Convert.ToInt32(cBoxMes.SelectedValue) == 12))
        btnMais.Enabled = false;
      else
        btnMais.Enabled = true;
      _aspectoGrid();
      this.gridCalandario.SelectionChanged += new System.EventHandler(this.gridCalandario_SelectionChanged);
      this.gridCalandario.Rows[_SelectDayy].Cells[_SelectDayx].Selected = true;
      _PositionOldSelect = _PositionSelect;
      _PositionSelect[0] = _SelectDayx;
      _PositionSelect[1] = _SelectDayy;
    }
    /// <summary>
    /// When rezize the parent form redesign the grid size
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void gridCalandario_Resize(object sender, EventArgs e)
    {
      _aspectoGrid();
    }
    /// <summary>
    /// When gridcalendarios datasource change redesign the grid
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void gridCalandario_DataSourceChanged(object sender, EventArgs e)
    {
      _aspectoGrid();
    }

    private void cBoxMes_SelectedIndexChanged(object sender, EventArgs e)
    {
      
      alterarMes();
    }

    private void txtAno_ValueChanged(object sender, EventArgs e)
    {
      alterarMes();
    }

    private void btnMenos_Click(object sender, EventArgs e)
    {
      if (Convert.ToInt32(cBoxMes.SelectedValue) == 1)
      {
        cBoxMes.SelectedIndex = 11;
        txtAno.Value = txtAno.Value - 1;
      }
      else
        cBoxMes.SelectedIndex = cBoxMes.SelectedIndex - 1;
      //alterarMes();
    }

    private void btnMais_Click(object sender, EventArgs e)
    {
      if (Convert.ToInt32(cBoxMes.SelectedValue) == 12)
      {
        cBoxMes.SelectedIndex = 0;
        txtAno.Value = txtAno.Value + 1;
      }
      else
        cBoxMes.SelectedIndex = cBoxMes.SelectedIndex + 1;
      //alterarMes();
    }

    private void gridCalandario_SelectionChanged(object sender, EventArgs e)
    {
      
      if (gridCalandario.SelectedCells.Count == 1)
      {
        _SelectDayx = gridCalandario.SelectedCells[0].ColumnIndex;
        _SelectDayy = gridCalandario.SelectedCells[0].RowIndex;
        _SelectDay = _dtMesArray[_SelectDayx, _SelectDayy];
        OnSelectionChanged();
        //if (_SelectDay.Month == Convert.ToInt16(cBoxMes.SelectedValue))
        //{
        //  OnSelectionChanged();
        //}
        //else if(_SelectDay.Month < Convert.ToInt16(cBoxMes.SelectedValue))
        //{
        //  btnMenos.PerformClick();
        //}
        //else if(_SelectDay.Month> Convert.ToInt16(cBoxMes.SelectedValue))
        //{
        //  btnMais.PerformClick();
        //}
      }
    }
    public DateTime DataSelecionada()
    {
      return _SelectDay;
    }

    

  }
}
